package com.mingliqiye.proxy.tcp;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.*;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class Porxy {
    private final InetSocketAddress localInetAddress;
    private final InetSocketAddress serverInetAddress;
    private ServerSocket socket;
    private final Map<String, PorxyItem> clientItemsList = new HashMap<>();


    Porxy(String[] sysArgs) {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            log.error("system is exiting.");
            log.error("system is exiting OK");
        }));
        log.info("Service is starting.");
        localInetAddress = new InetSocketAddress(sysArgs[0], Integer.parseInt(sysArgs[1]));
        serverInetAddress = new InetSocketAddress(sysArgs[2], Integer.parseInt(sysArgs[3]));
        init();
    }

    private void init() {
        try {
            log.info("Creating Sockets...");
            socket = new ServerSocket(localInetAddress.getPort(), 50, localInetAddress.getAddress());
            socket.setSoTimeout(1);
            log.info("Testing Server Sockets...");
            Socket serverSocket = new Socket();
            serverSocket.connect(serverInetAddress);
            serverSocket.close();
            log.info("Test Server Sockets OK!!");
            log.info("Starting...");
        } catch (
                Exception e) {
            log.error("{}:{}", e.getClass().getName(), e.getMessage());
        }
    }

    public void addClient(Socket clientSocket) {
        PorxyItem clientProxyItem = new PorxyItem(clientSocket, serverInetAddress, this);
        String clientId = clientProxyItem.getId();
        clientItemsList.put(clientId, clientProxyItem);
        log.info("Client {} Connection successful current clients is {}", clientId, clientItemsList.size());
        clientProxyItem.start();
    }

    public void removerClinet(String id) {
        if (clientItemsList.containsKey(id)){
            clientItemsList.remove(id);
            log.info("Client {} has disconnected current clients is {}", id, clientItemsList.size());
        }

    }

    public void start() {
        log.info("The service is up and running on {}:{} and on {}", localInetAddress.getHostString(), localInetAddress.getPort(), ManagementFactory.getRuntimeMXBean().getName());
        log.info("Waiting for client to connect");
        while (true) {
            try {
                addClient(socket.accept());
            } catch (
                    SocketTimeoutException e) {
            } catch (
                    IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
